#include "KMultiplexor.h"
#include "KKey.h"
#include "KSockContext.h"
#include "KSocketIocp.h"

void KDef::RequestInfo::failure(AcceptRequest *request)
{
    KDebugLib("Processing accept failed...");
    switch (error) {
    case ERROR_NETNAME_DELETED:
    case ERROR_SEM_TIMEOUT:
        delete request->client;
        request->client = NULL;
        node->removeRequest(request);
        m_host->accept(node->getSocket(), request);
        break;
    default:
        m_host->onError(node->getSocket(), KDef::ErrorFailedAccept, error);
        node->removeRequest(request);
        delete request;
        break;
    }
}

void KDef::RequestInfo::failure(ConnectRequest *request)
{
    KDebugLib("Processing connect failed...");
    m_host->onError(node->getSocket(), KDef::ErrorFailedConnect, error);
    node->removeRequest(request);
    delete request;
}

void KDef::RequestInfo::failure(DisconnRequest *request)
{
    KDebugLib("Processing disconnect failed...");
    m_host->onError(node->getSocket(), KDef::ErrorFailedDisconnect, error);
    node->removeRequest(request);
    delete request;
}

void KDef::RequestInfo::failure(IoRequest *request)
{
    if (request->isRecv) {
        KDebugLib("Processing receive failed...");
        m_host->onError(node->getSocket(), KDef::ErrorFailedReceive, error);
    } else {
        KDebugLib("Processing send failed...");
        m_host->onError(node->getSocket(), KDef::ErrorFailedSend, error);
    }
    node->removeRequest(request);
    delete request->key;
    request->key = NULL;
    m_host->m_pool.pushFront(request);
}

void KDef::RequestInfo::failure(TransmitRequest *request)
{
    KDebugLib("Processing transmit failed...");
    m_host->onError(node->getSocket(), KDef::ErrorFailedTransmit, error);
    node->removeRequest(request);
    delete request;
}

void KDef::RequestInfo::success(AcceptRequest *request)
{
    KSocket *acceptor = node->getSocket();
    KAutoPtr<KSocketContext> client(static_cast<KSocketContext *>(request->client));
    request->client = NULL;
    if (!client->updateAcceptContextWith(*acceptor)) {
        KDebugLib("Failed to update accept socket context");
        m_host->onError(client, KDef::ErrorUpdateContext, WSAGetLastError());
    }
    if (!m_host->m_iocp->addSocket(client, reinterpret_cast<ULONG_PTR>(static_cast<KDef::SocketContext *>(client)))) {
        DWORD lastErr = GetLastError();
        KDebugLib("Failed to add client to i/o completion port: %d", lastErr);
        m_host->onError(client, KDef::ErrorAddToIocp, lastErr);
    } else {
        m_host->m_context.pushFront(client);
        m_host->onAccepted(client, acceptor->key());
        client.release();
    }
    node->removeRequest(request);
    m_host->accept(acceptor, request);
}

void KDef::RequestInfo::success(ConnectRequest *request)
{
    KSocket *connector = node->getSocket();
    if (!connector->updateConnectContext()) {
        KDebugLib("Failed to update connect socket context");
        m_host->onError(connector, KDef::ErrorUpdateContext, WSAGetLastError());
    }
    m_host->onConnected(connector);
    node->removeRequest(request);
    delete request;
}

void KDef::RequestInfo::success(DisconnRequest *request)
{
    m_host->onDisconnected(node->getSocket());
    node->removeRequest(request);
    delete request;
}

void KDef::RequestInfo::success(IoRequest *request)
{
    if (request->isRecv) {
        if (bytes == 0) {
            m_host->onError(node->getSocket(), KDef::ErrorDisconnRecv, 0);
        } else {
            m_host->onReceived(node->getSocket(), request->key,
                reinterpret_cast<void *&>(request->buffer.buf), bytes, more);
            if (request->buffer.buf == NULL) {
                request->buffer.len = 0;
            }
        }
    } else {
        if (bytes == 0) {
            m_host->onError(node->getSocket(), KDef::ErrorDisconnSend, 0);
        } else {
            if ((request->bytesSent += bytes) < request->bytesTotal) {
                WSABUF rest;
                rest.buf = request->buffer.buf + request->bytesSent;
                rest.len = request->bytesTotal - request->bytesSent;
                if (m_host->sendAgain(node->getSocket(), request, &rest)) {
                    KDebugLib("Sending the rest...");
                    return;
                }
            } else {
                m_host->onSent(node->getSocket(), request->key,
                    reinterpret_cast<void *&>(request->buffer.buf), request->bytesTotal);
                if (request->buffer.buf == NULL) {
                    request->buffer.len = 0;
                }
            }
        }
    }
    node->removeRequest(request);
    delete request->key;
    request->key = NULL;
    m_host->m_pool.pushFront(request);
}

void KDef::RequestInfo::success(MessageRequest *request)
{
    m_host->onMessage(node->getSocket(), request->key);
    node->removeRequest(request);
    delete request;
}

void KDef::RequestInfo::success(TransmitRequest *request)
{
    m_host->onTransmitted(node->getSocket(), request->key, request->file, bytes);
    node->removeRequest(request);
    delete request;
}

void KDef::BasicRequest::onFailureImp(RequestInfo &info)
{
    KDebugLib("Warning: virtual function KDef::BasicRequest::onFailureImp() called");
}

void KDef::BasicRequest::onSuccessImp(RequestInfo &info)
{
    KDebugLib("Warning: virtual function KDef::BasicRequest::onSuccessImp() called");
}

KDef::AcceptRequest::~AcceptRequest()
{
    delete client;
}

void KDef::AcceptRequest::onFailureImp(RequestInfo &info)
{
    info.failure(this);
}

void KDef::AcceptRequest::onSuccessImp(RequestInfo &info)
{
    info.success(this);
}

void KDef::ConnectRequest::onFailureImp(RequestInfo &info)
{
    info.failure(this);
}

void KDef::ConnectRequest::onSuccessImp(RequestInfo &info)
{
    info.success(this);
}

void KDef::DisconnRequest::onFailureImp(RequestInfo &info)
{
    info.failure(this);
}

void KDef::DisconnRequest::onSuccessImp(RequestInfo &info)
{
    info.success(this);
}

KDef::IoRequest::~IoRequest()
{
    delete key;
    delete[] buffer.buf;
}

void KDef::IoRequest::free(void *data)
{
    delete[] static_cast<CHAR *>(data);
}

void KDef::IoRequest::resize(size_t bufSize, bool expand)
{
    bytesSent = bytesTotal = 0;
    if (expand && bufSize <= buffer.len) {
        return;
    }
    delete[] buffer.buf;
    if (bufSize > 0) {
        buffer.buf = new CHAR[bufSize];
        assert(buffer.buf != NULL);
    } else {
        buffer.buf = NULL;
    }
    buffer.len = bufSize;
}

void KDef::IoRequest::onFailureImp(RequestInfo &info)
{
    info.failure(this);
}

void KDef::IoRequest::onSuccessImp(RequestInfo &info)
{
    info.success(this);
}

KDef::MessageRequest::~MessageRequest()
{
    delete key;
}

void KDef::MessageRequest::onFailureImp(RequestInfo &info)
{
    // Should not reach
    assert(false);
    info.success(this);
}

void KDef::MessageRequest::onSuccessImp(RequestInfo &info)
{
    info.success(this);
}

KDef::TransmitRequest::~TransmitRequest()
{
    delete key;
}

void KDef::TransmitRequest::onFailureImp(RequestInfo &info)
{
    info.failure(this);
}

void KDef::TransmitRequest::onSuccessImp(RequestInfo &info)
{
    info.success(this);
}